방문자 디자인 패턴의 전통적인 구현방식은 이중 디스패치를 이용한다.
이중 디스패치를 구현할 때, 네이밍 관례
- 방문자의 멤버 함수는 visit() 이름을 사용
- 클래스 계층마다 구현되는 멤버 함수의 이름은 accept() 이름을 사용
struct Expression{
virtual void accept(ExpressionVisitor* visitor)=0;
};
ExpressionVisitor는 추상 클래스로 여러 가지 방문자들(ExpressionPrinter, ExpressionEvaluator)의
베이스 클래스이다.
void accept(ExpressionVisitor* visitor) override {
visitor->visit(this);
}
Expression을 상속받는 모든 클래스(DoubleExpression, AdditionExpression)에 위와 같이
accept를 구현
struct ExpressionVisitor{
virtual void visit(DoubleExpression* de)=0;
virtual void visit(AdditionExpression* ae)=0;
};
struct ExpressionPrinter: ExpressionVisitor{
ostringstream oss;
string str() const { return oss.str(); }
void visit(DoubleExpression* de) override;
void visit(AdditionExpression* ae) override;
};
void ExpressionPrinter::visit(AdditionExpression* ae){
oss<<"(";
ae->left->accept(this);
oss<<"+";
ae->right->accept(this);
oss<<")";
}
void main(void){
auto e=new AdditionExpression{
};
ostringstream oss;
ExpressionPrinter ep;
ep.visit(e);
cout<<ep.str()<<endl;
}
하위 Expression 자체에서 멤버 함수 호출이 일어남.
방문자 추가하기
struct ExpressionEvaluator: ExpressionVisitor{
double result;
void visit(DoubleExpression* de) override;
void visit(AdditionExpression* ae) override;
};
void ExpressionEvaluator::visit(DoubleExpression* de){
result=de->value;
}
void ExpressionEvaluator::visit(AdditionExpression* ae){
ae->left->accept(this);
auto temp=result;
ae->right->accept(this);
result+=temp;
}
auto e=new AdditionExpression{
}
ExpressionPrinter printer;
ExpressionEvaluator evaluator;
printer.visit(e);
evaluator.visit(e);
cout<<printer.str() <<" = "<<evaluator.result<<endl;